using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml;
using System.Net;
using System.IO;
using System.Web.Services.Protocols;
using System;
using Microsoft.Crm.Sdk.Proxy;


namespace CRM_Perf_BenchMark.EmailMatching
{
    /// <summary>
    /// Summary description for DMUnitTest1
    /// </summary>
    [TestClass]
    public class EmailMatchingUnitTests
    {
        CRMEntity sender;
        CRMEntity[] recipients;

        CrmService Proxy1 = null;
        CrmService Proxy2 = null;

        TestContext testContextInstance1;

        private static string resultDir = Directory.GetDirectoryRoot(Directory.GetCurrentDirectory()) + @"PerfResult";

        public EmailMatchingUnitTests()
        {
        }

        public TestContext TestContext
        {
            get { return testContextInstance1; }
            set { testContextInstance1 = value; }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        [ClassInitialize()]
        public static void MyClassInitialize(TestContext testContext)
        {
            //this is the directory where all perf results are stored
            string perfResultDir = Directory.GetDirectoryRoot(Directory.GetCurrentDirectory()) + @"PerfResult";
            if (!Directory.Exists(perfResultDir))
                Directory.CreateDirectory(perfResultDir);
        }

        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }



        // Use TestInitialize to run code before running each test 
        [TestInitialize()]
        public void TestInitialize()
        {
            System.Collections.Hashtable userProps = new System.Collections.Hashtable();
            
            if (TestContext.Properties.Contains("UserRole"))
            {               
                userProps.Add("role", (string)TestContext.Properties["UserRole"]);                
            }

            Guid orgId = EntityManager.Instance.GetRandomOrg();

            sender = EntityManager.Instance.GetNextUser(userProps, orgId);

            recipients = new CRMEntity[] {
				EntityManager.Instance.GetNextUser(userProps, orgId),
				EntityManager.Instance.GetNextUser(userProps, orgId),
				EntityManager.Instance.GetNextUser(userProps, orgId),
				EntityManager.Instance.GetNextUser(userProps, orgId)};

            if ((Proxy1 = SetupWebService(sender)) == null)
            {
                System.Diagnostics.Trace.WriteLine("Setup Web Service did not succeed");
            }

            if ((Proxy2 = SetupWebService(recipients[0])) == null)
            {
                System.Diagnostics.Trace.WriteLine("Setup Web Service did not succeed");
            }
        }

        public CrmService SetupWebService(CRMEntity user)
        {
            CrmService Proxy = new CrmService();

            string domain = string.Empty;
            string userName = string.Empty;
            string crmServer = string.Empty;
            string apiServer = string.Empty;
            string password = string.Empty;
            string organization = string.Empty;
            string crmTicket = string.Empty;
            NetworkCredential nc;

            try
            {
                string[] splits = user["domainname"].Split(new char[] { '\\' }, 2, StringSplitOptions.RemoveEmptyEntries);
                if (splits.Length > 1)
                {
                    domain = splits[0];
                    userName = splits[1];
                }

                crmServer = user["CrmServer"];
                apiServer = user["ApiServer"];
                password = user["userpassword"];
                organization = user["organizationname"];

                Proxy.Url = apiServer + "/MSCRMServices/2007/CrmService.asmx";
                
                
                Proxy.UnsafeAuthenticatedConnectionSharing = true;
                nc = new NetworkCredential(userName, password, domain);
                Proxy.ConnectionGroupName = domain + "\\" + userName;
                Proxy.Credentials = nc;
                
                CrmAuthenticationToken token = new CrmAuthenticationToken();
                token.OrganizationName = organization;                
                token.AuthenticationType = AuthenticationType.AD;
                                
                Proxy.CrmAuthenticationTokenValue = token;
                return Proxy;
            }
            catch (Exception e)
            {
                System.Diagnostics.Trace.WriteLine("Exception creating the CrmService - " + e.ToString());
                throw;
            }
        }

        // Use TestCleanup to run code after each test has run
        [TestCleanup()]
        public void TestCleanup()
        {
            EntityManager.Instance.FreeEntity(sender);
            for (int i = 0; i < recipients.Length; i++)
            {
                EntityManager.Instance.FreeEntity(recipients[i]);
            }
            Proxy1 = null;
            Proxy2 = null;
        }

        #endregion

        #region Individual Test Cases

        [TestMethod()]
        public void OutgoingTest()
        {
            string subject = this.GenerateRandomText(5);

            string recipient5 = "random_2@external.address.com";

            DeliverPromoteEmailRequest deliverPromoteEmailRequest = new DeliverPromoteEmailRequest();

            deliverPromoteEmailRequest.Subject = subject;

            deliverPromoteEmailRequest.From = ConstructAddressList(new CRMEntity[] { sender });

            deliverPromoteEmailRequest.To = ConstructAddressList(recipients);

            deliverPromoteEmailRequest.Cc = recipient5;

            deliverPromoteEmailRequest.Bcc = String.Empty;

            deliverPromoteEmailRequest.MessageId = Guid.NewGuid().ToString();

            deliverPromoteEmailRequest.ReceivedOn = CrmTypes.CreateCrmDateTimeFromUser(DateTime.Now);

            deliverPromoteEmailRequest.SubmittedBy = deliverPromoteEmailRequest.From;

            deliverPromoteEmailRequest.Importance = "high";

            deliverPromoteEmailRequest.Body = GenerateRandomText(1000);

            deliverPromoteEmailRequest.Attachments = new BusinessEntityCollection();

            deliverPromoteEmailRequest.Attachments.EntityName = "activitymimeattachment";

            deliverPromoteEmailRequest.Attachments.BusinessEntities = new activitymimeattachment[0];

            DateTime start = DateTime.UtcNow;

            DeliverPromoteEmailResponse deliverPromoteEmailResponse = Proxy1.Execute(
                deliverPromoteEmailRequest) as DeliverPromoteEmailResponse;

            SendEmailRequest sendEmailRequest = new SendEmailRequest();

            sendEmailRequest.EmailId = deliverPromoteEmailResponse.EmailId;

            sendEmailRequest.IssueSend = false;

            sendEmailRequest.TrackingToken = String.Empty;

            SendEmailResponse sendEmailResponse = Proxy1.Execute(
                sendEmailRequest) as SendEmailResponse;

            DateTime end = DateTime.UtcNow;

            System.Diagnostics.Trace.WriteLine("OutgoingTest: DeliverPromote+Send - " + TimeSpan.FromTicks(end.Ticks - start.Ticks).TotalMilliseconds.ToString());
        }

        [TestMethod()]
        public void IncomingSalesTest()
        {
            SetEmailFilteringMethod(recipients[0], 0, Proxy2);

            string external = "recipient_1@external.domain.com";

            string subject = this.GenerateRandomText(5);

            DeliverPromoteEmailRequest deliverPromoteEmailRequest = new DeliverPromoteEmailRequest();

            deliverPromoteEmailRequest.Subject = subject;

            deliverPromoteEmailRequest.From = ConstructAddressList(new CRMEntity[] { sender });

            deliverPromoteEmailRequest.To = ConstructAddressList(recipients);

            deliverPromoteEmailRequest.Cc = external;

            deliverPromoteEmailRequest.Bcc = String.Empty;

            deliverPromoteEmailRequest.MessageId = Guid.NewGuid().ToString();

            deliverPromoteEmailRequest.ReceivedOn = CrmTypes.CreateCrmDateTimeFromUser(DateTime.Now);

            deliverPromoteEmailRequest.SubmittedBy = deliverPromoteEmailRequest.From;

            deliverPromoteEmailRequest.Importance = "high";

            deliverPromoteEmailRequest.Body = GenerateRandomText(1000);

            deliverPromoteEmailRequest.Attachments = new BusinessEntityCollection();

            deliverPromoteEmailRequest.Attachments.EntityName = "activitymimeattachment";

            deliverPromoteEmailRequest.Attachments.BusinessEntities = new activitymimeattachment[0];

            DeliverPromoteEmailResponse deliverPromoteEmailResponse = Proxy1.Execute(
                deliverPromoteEmailRequest) as DeliverPromoteEmailResponse;

            // Simulate email delivery 

            CheckIncomingEmailRequest checkIncomingEmailRequest = new CheckIncomingEmailRequest();

            checkIncomingEmailRequest.Subject = subject;

            checkIncomingEmailRequest.To = deliverPromoteEmailRequest.To;

            checkIncomingEmailRequest.From = deliverPromoteEmailRequest.From;

            checkIncomingEmailRequest.Cc = String.Empty;

            checkIncomingEmailRequest.Bcc = String.Empty;

            checkIncomingEmailRequest.MessageId = deliverPromoteEmailRequest.MessageId;

            DateTime start = DateTime.UtcNow;

            CheckIncomingEmailResponse incomingResponse = Proxy2.Execute(
                checkIncomingEmailRequest) as CheckIncomingEmailResponse;

            DeliverIncomingEmailRequest deliverIncomingRequest = new DeliverIncomingEmailRequest();

            deliverIncomingRequest.Attachments = deliverPromoteEmailRequest.Attachments;

            deliverIncomingRequest.Subject = subject;

            deliverIncomingRequest.To = deliverPromoteEmailRequest.To;

            deliverIncomingRequest.From = deliverPromoteEmailRequest.From;

            deliverIncomingRequest.Cc = deliverPromoteEmailRequest.Cc;

            deliverIncomingRequest.Bcc = deliverPromoteEmailRequest.Bcc;

            deliverIncomingRequest.MessageId = deliverPromoteEmailRequest.MessageId;

            deliverIncomingRequest.Body = deliverPromoteEmailRequest.Body;

            deliverIncomingRequest.Importance = "high";

            deliverIncomingRequest.ReceivedOn = CrmTypes.CreateCrmDateTimeFromUser(DateTime.Now);

            deliverIncomingRequest.SubmittedBy = deliverPromoteEmailRequest.SubmittedBy;

            DeliverIncomingEmailResponse deliverIncomingEmailResponse = Proxy2.Execute(
                deliverIncomingRequest) as DeliverIncomingEmailResponse;

            DateTime end = DateTime.UtcNow;

            System.Diagnostics.Trace.WriteLine("IncomingTest: CheckIncoming+DeliverIncoming - " + TimeSpan.FromTicks(end.Ticks - start.Ticks).TotalMilliseconds.ToString());
        }

        [TestMethod()]
        public void IncomingSupportTest()
        {
            SetEmailFilteringMethod(recipients[0], 1, Proxy2);

            string external = "recipient_1@external.domain.com";

            string subject = this.GenerateRandomText(5);

            DeliverPromoteEmailRequest deliverPromoteEmailRequest = new DeliverPromoteEmailRequest();

            deliverPromoteEmailRequest.Subject = subject;

            deliverPromoteEmailRequest.From = ConstructAddressList(new CRMEntity[] { sender });

            deliverPromoteEmailRequest.To = ConstructAddressList(recipients);

            deliverPromoteEmailRequest.Cc = external;

            deliverPromoteEmailRequest.Bcc = String.Empty;

            deliverPromoteEmailRequest.MessageId = Guid.NewGuid().ToString();

            deliverPromoteEmailRequest.ReceivedOn = CrmTypes.CreateCrmDateTimeFromUser(DateTime.Now);

            deliverPromoteEmailRequest.SubmittedBy = deliverPromoteEmailRequest.From;

            deliverPromoteEmailRequest.Importance = "high";

            deliverPromoteEmailRequest.Body = GenerateRandomText(1000);

            deliverPromoteEmailRequest.Attachments = new BusinessEntityCollection();

            deliverPromoteEmailRequest.Attachments.EntityName = "activitymimeattachment";

            deliverPromoteEmailRequest.Attachments.BusinessEntities = new activitymimeattachment[0];

            DeliverPromoteEmailResponse deliverPromoteEmailResponse = Proxy1.Execute(
                deliverPromoteEmailRequest) as DeliverPromoteEmailResponse;

            // Simulate email delivery 

            CheckIncomingEmailRequest checkIncomingEmailRequest = new CheckIncomingEmailRequest();

            checkIncomingEmailRequest.Subject = subject;

            checkIncomingEmailRequest.To = deliverPromoteEmailRequest.To;

            checkIncomingEmailRequest.From = deliverPromoteEmailRequest.From;

            checkIncomingEmailRequest.Cc = String.Empty;

            checkIncomingEmailRequest.Bcc = String.Empty;

            checkIncomingEmailRequest.MessageId = deliverPromoteEmailRequest.MessageId;

            DateTime start = DateTime.UtcNow;

            CheckIncomingEmailResponse incomingResponse = Proxy2.Execute(
                checkIncomingEmailRequest) as CheckIncomingEmailResponse;

            DeliverIncomingEmailRequest deliverIncomingRequest = new DeliverIncomingEmailRequest();

            deliverIncomingRequest.Attachments = deliverPromoteEmailRequest.Attachments;

            deliverIncomingRequest.Subject = subject;

            deliverIncomingRequest.To = deliverPromoteEmailRequest.To;

            deliverIncomingRequest.From = deliverPromoteEmailRequest.From;

            deliverIncomingRequest.Cc = deliverPromoteEmailRequest.Cc;

            deliverIncomingRequest.Bcc = deliverPromoteEmailRequest.Bcc;

            deliverIncomingRequest.MessageId = deliverPromoteEmailRequest.MessageId;

            deliverIncomingRequest.Body = deliverPromoteEmailRequest.Body;

            deliverIncomingRequest.Importance = "high";

            deliverIncomingRequest.ReceivedOn = CrmTypes.CreateCrmDateTimeFromUser(DateTime.Now);

            deliverIncomingRequest.SubmittedBy = deliverPromoteEmailRequest.SubmittedBy;

            DeliverIncomingEmailResponse deliverIncomingEmailResponse = Proxy2.Execute(
                deliverIncomingRequest) as DeliverIncomingEmailResponse;

            DateTime end = DateTime.UtcNow;

            System.Diagnostics.Trace.WriteLine("IncomingTest: CheckIncoming+DeliverIncoming - " + TimeSpan.FromTicks(end.Ticks - start.Ticks).TotalMilliseconds.ToString());
        }

        #endregion

        #region Private Methods

        private string GenerateRandomText(int words)
        {
            StringBuilder subject = new StringBuilder();

            for (int i = 0; i < words; i++)
            {
                subject.Append(Guid.NewGuid().ToString());

                subject.Append(" ");
            }

            return subject.ToString();
        }

        private string ConstructAddressList(CRMEntity[] users)
        {
            StringBuilder address = new StringBuilder();

            for (int i = 0; i < users.Length; i++)
            {
                address.Append(users[i]["InternalEmailAddress"]);
                address.Append(";");
            }
            return address.ToString();
        }

        private void SetEmailFilteringMethod(CRMEntity user, int filterMethod, CrmService Proxy)
        {
            Guid id = new Guid(user["systemuserid"]);

            usersettings userSettings = new usersettings();

            userSettings.systemuserid = CrmTypes.CreateKey(id);

            Picklist picklist = new Picklist();

            picklist.Value = filterMethod;

            userSettings.incomingemailfilteringmethod = picklist;

            UpdateUserSettingsSystemUserRequest updateUserSettingsSystemUserRequest = new UpdateUserSettingsSystemUserRequest();

            updateUserSettingsSystemUserRequest.UserId = id;

            updateUserSettingsSystemUserRequest.Settings = userSettings;

            Proxy.Execute(updateUserSettingsSystemUserRequest);            
        }

        #endregion
    }
}
